﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OverStore.Configuration;
using OverStore.Configuration.Builder;
using System.Data.SqlServerCe;
using OverStore.Configuration.Builder.Fluent;
using OverStore.Configuration.Components;
using OverStore.Exceptions;
using OverStore.Runtime.Storage;

namespace OverStore.TutorialAsTest.UnitTest.Configuration
{
    [TestClass]
    public class CreateConfigurationTableMapping
    {
        class SimpleClass
        {
            private Guid _Id;

            public Guid Id
            {
                get { return _Id; }
                set { _Id = value; }
            }

            public string Name { get; set; }

            public DateTime CreationDate { get; set; }

            public int Type { get; set; }
        }

        public static OverStoreConfiguration CreateConfiguration(string connectionString)
        {
            return OverStoreFluent.Configure()
                .LogToConsole()
                .ConnectToDatabase<SqlCeConnection>(connectionString, ProcessOpenedReadersMode.ForciblyCloseReaders)
				.MapClassToTable<SimpleClass, Guid>("SimpleClass")
					.MapKey("Id", e => e.Id, (e, i) => e.Id = i, Component.IdentifierGenerator.Guid<SimpleClass>())
                    .MapScalarValue<string>("Name", e => e.Name, (e, i) => e.Name = i)
                    .MapScalarValue<DateTime>("CreationDate", e => e.CreationDate, (e, v) => e.CreationDate = v)
                    .MapScalarValue<int>("Type", e => e.Type, (e, v) => e.Type = v)
				.EndTableMapping()
			.End();
        }

        #region GetByIdentifier object

        [TestMethod]
        public void TableMapping_GetObject_CorrectContent()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            using (IPersistenceSession session = CreateConfiguration(connectionString).CreateSession())
            {
                Guid id = new Guid("f30c02ce-33fd-4dda-8228-500609c8ee7b");
                SimpleClass instance = session.GetByIdentifier<SimpleClass, Guid>(id);
                Assert.AreEqual(id, instance.Id);
                Assert.AreEqual("NewClass", instance.Name);
                Assert.AreEqual(0, instance.Type);
            }
        }

        [TestMethod]
        public void TableMapping_GetObject_IdentityMapping()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var config = CreateConfiguration(connectionString);
            using (IPersistenceSession session = config.CreateSession())
            {
                Guid id = new Guid("f30c02ce-33fd-4dda-8228-500609c8ee7b");
                SimpleClass instance = session.GetByIdentifier<SimpleClass, Guid>(id);
                SimpleClass reference = session.GetByIdentifier<SimpleClass, Guid>(id);

                Assert.AreSame(instance, reference);
                using (IPersistenceSession secondSession = config.CreateSession())
                {
                    SimpleClass secondSessionBound = secondSession.GetByIdentifier<SimpleClass, Guid>(id);
                    Assert.AreNotSame(instance, secondSessionBound);
                    Assert.AreEqual(instance.Id, secondSessionBound.Id);
                    Assert.AreEqual(instance.CreationDate, secondSessionBound.CreationDate);
                    Assert.AreEqual(instance.Name, secondSessionBound.Name);
                    Assert.AreEqual(instance.Type, secondSessionBound.Type);
                }
            }
        }

        [TestMethod]
        [ExpectedException(typeof(PersistenceOperationFailedException))]
        public void TableMapping_GetObject_InstanceMissing()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var config = CreateConfiguration(connectionString);
            using (IPersistenceSession session = config.CreateSession())
            {
                Guid id = new Guid("DE11C058-1D29-425b-AAFD-FDF91509E263");
                SimpleClass instance = session.GetByIdentifier<SimpleClass, Guid>(id);
            }
        }

        #endregion

        #region ReloadUsingData

        [TestMethod]
        public void TableMapping_ReloadObject()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var config = CreateConfiguration(connectionString);
            using (IPersistenceSession session = config.CreateSession())
            {
                Guid id = new Guid("f30c02ce-33fd-4dda-8228-500609c8ee7b");
                SimpleClass instance = session.GetByIdentifier<SimpleClass, Guid>(id);
                instance.Name = "11212";
                session.Reload(instance);

                Assert.AreEqual(id, instance.Id);
                Assert.AreEqual("NewClass", instance.Name);
                Assert.AreEqual(0, instance.Type);

                instance.Name = "22";
                session.Reload(instance);
                Assert.AreEqual("NewClass", instance.Name);

                Assert.AreSame(instance, session.GetByIdentifier<SimpleClass, Guid>(id));
            }
        }

        #endregion

        #region SaveAll object

        [TestMethod]
        public void TableMapping_SaveObject()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var config = CreateConfiguration(connectionString);
            using (IPersistenceSession session = config.CreateSession())
            {
                Guid id = new Guid("f30c02ce-33fd-4dda-8228-500609c8ee7b");
                SimpleClass instance = session.GetByIdentifier<SimpleClass, Guid>(id);
                instance.Name = "ChangedName";
                session.Save(instance);
                using (IPersistenceSession second = config.CreateSession())
                {
                    SimpleClass reference = second.GetByIdentifier<SimpleClass, Guid>(id);
                    Assert.AreNotSame(instance, reference);
                    Assert.AreEqual(instance.Name, reference.Name);

                    reference.Name = "NewClass";
                    second.Save(reference);
                }

                session.Reload(instance);
                Assert.AreEqual("NewClass", instance.Name);
            }
        }

        #endregion

        #region MarkAsDeleted

        [TestMethod]
        public void TableMapping_MarkObjectAsDeleted()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var config = CreateConfiguration(connectionString);
            using (IPersistenceSession session = config.CreateSession())
            {
                Guid id = new Guid("8f10f298-b4a3-4686-ab7e-e565f8bee70a");
                SimpleClass instance = session.GetByIdentifier<SimpleClass, Guid>(id);
                session.MarkAsDeleted(instance);
                session.Reload(instance);
                session.Save(instance);
                using (IPersistenceSession second = config.CreateSession())
                {
                    var reference = second.GetByIdentifier<SimpleClass, Guid>(id);
                    Assert.AreEqual(instance.Id, reference.Id);
                }

                session.MarkAsDeleted(instance);
                session.Save(instance);
                bool isFailed = false;
                using (IPersistenceSession second = config.CreateSession())
                {
                    try
                    {
                        SimpleClass reference = second.GetByIdentifier<SimpleClass, Guid>(id);
                    }
                    catch (PersistenceOperationFailedException)
                    {
                        isFailed = true;
                    }
                    if (!isFailed)
                        Assert.Fail("Object does not deleted");
                    var simpleClass = new SimpleClass { Id = id, CreationDate = DateTime.Now, Name = "sdad", Type = 3 };
                    second.Save(simpleClass);
                }
            }
        }

        #endregion

        #region Object state management

        [TestMethod]
        public void TableMapping_AddObject()
        {
            var connectionString = TestHelper.CreateTestDbCopyAndBuildConnectionString();
            var config = CreateConfiguration(connectionString);
            using (IPersistenceSession session = config.CreateSession())
            {
                Guid id = new Guid("41297FDA-E4ED-4475-8C8E-04AD27EF6C73");

                using (IPersistenceSession secondSession = config.CreateSession())
                {
                    try
                    {

                        var instance = secondSession.GetByIdentifier<SimpleClass, Guid>(id);
                        Assert.Inconclusive("The SimpleClass with identifier {0} available in data source",
                            id);
                    }
                    catch (PersistenceOperationFailedException)
                    {
                        // Do nothing, normal behaviour
                    }
                }

                SimpleClass newInstance = new SimpleClass()
                {
                    Id = id,
                    Type = 3,
                    Name = "Instance",
                    CreationDate = DateTime.Now
                };

                session.Add(newInstance);

                Assert.AreSame(newInstance, session.GetByIdentifier<SimpleClass, Guid>(newInstance.Id));

                //Assert.AreEqual(ObjectChangeState.Unknown, session.GetObjectState(newInstance));
            }
        }

        #endregion
    }
}
